#ifndef KASCALE_SOCKET_H
#define KASCALE_SOCKET_H

#include "Config.h"
#include "BasicTypes.h"
#include "string.h"
#ifdef WIN32

#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>

typedef unsigned short  sa_family_t;
typedef u_int16_t		in_port_t;
typedef long			suseconds_t;

#ifndef PATH_MAX
#define PATH_MAX 512
#endif

#else

#include <sys/socket.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <net/if.h>
#ifndef PATH_MAX
#define PATH_MAX 255
#endif
#define INVALID_SOCKET		-1
#define SOCKET_ERROR		-1
typedef int SOCKET;

#if !defined(IFF_POINTTOPOINT)
#define IFF_POINTTOPOINT IFF_POINTOPOINT
#endif

#endif

#ifndef LLONG_MAX
	 #define LLONG_MAX 9223372036854775807LL
#endif

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <vector>
#include <list>
#include <set>
#include <sstream>
#include <iostream>
#include <string>
using namespace std;

namespace kascale
{
#ifdef WIN32

#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif

inline const char *inet_ntop4(const u_int8_t *src, char *dest, socklen_t len)
{
	ostringstream ostr;
	ostr << (int)src[0] << '.' << (int)src[1] << '.' << (int)src[2] << '.' << (int)src[3];
	string ret = ostr.str();
	if((int)ret.length() + 1 > len)
	{
		errno = ENOSPC;
		return NULL;
	}
	strncpy(dest, ret.c_str(), ret.length() + 1);
	return dest;
}
inline const char *inet_ntop6(const u_int8_t *src, char *dest, socklen_t len)
{
	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
	struct { int base, len; } best, cur;
	const int IN6ADDRSZ = sizeof(in6_addr);
	const int INT16SZ = sizeof(int16_t);
	u_int words[IN6ADDRSZ / INT16SZ];
	int i;

	/*
	 * Preprocess:
	 *	Copy the input (bytewise) array into a wordwise array.
	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
	 */
	memset(words, '\0', sizeof words);
	for (i = 0; i < IN6ADDRSZ; i++)
		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
	best.base = -1;
	cur.base = -1;
	for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
		if (words[i] == 0) {
			if (cur.base == -1)
				cur.base = i, cur.len = 1;
			else
				cur.len++;
		} else {
			if (cur.base != -1) {
				if (best.base == -1 || cur.len > best.len)
					best = cur;
				cur.base = -1;
			}
		}
	}
	if (cur.base != -1) {
		if (best.base == -1 || cur.len > best.len)
			best = cur;
	}
	if (best.base != -1 && best.len < 2)
		best.base = -1;

	/*
	 * Format the result.
	 */
	tp = tmp;
	for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
		/* Are we inside the best run of 0x00's? */
		if (best.base != -1 && i >= best.base &&
		    i < (best.base + best.len)) {
			if (i == best.base)
				*tp++ = ':';
			continue;
		}
		/* Are we following an initial run of 0x00s or any real hex? */
		if (i != 0)
			*tp++ = ':';
		/* Is this address an encapsulated IPv4? */
		if (i == 6 && best.base == 0 &&
		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
				return (NULL);
			tp += strlen(tp);
			break;
		}
		tp += SPRINTF((tp, "%x", words[i]));
	}
	/* Was it a trailing run of 0x00's? */
	if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
		*tp++ = ':';
	*tp++ = '\0';

	/*
	 * Check for overflow, copy, and we're done.
	 */
	if ((socklen_t)(tp - tmp) > len) {
		errno = ENOSPC;
		return (NULL);
	}
	strcpy(dest, tmp);
	return dest;
}

inline const char * inet_ntop(int af, const void *src, char *dest, socklen_t len)
{
	switch (af) 
	{
	case AF_INET:
		return (inet_ntop4((const u_int8_t*)src, dest, len));
	case AF_INET6:
		return (inet_ntop6((const u_int8_t*)src, dest, len));
	default:
#ifdef WIN32
		WSASetLastError(WSAEAFNOSUPPORT);
#else
		errno = EAFNOSUPPORT;
#endif
		cout << "Address family not supported." << endl;
		return (NULL);
	}
}

#ifndef INADDRSZ
#define	INADDRSZ	4
#endif


/* int
 * inet_pton4(src, dst, pton)
 *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
 *	when last arg is 1: inet_pton(). decimal dotted-quad only.
 * return:
 *	1 if `src' is a valid input, else 0.
 * notice:
 *	does not touch `dst' unless it's returning 1.
 * author:
 *	Paul Vixie, 1996.
 */
inline int inet_pton4(const char *src, u_char *dst, int pton)
{
	u_int val;
	u_int digit;
	int base, n;
	unsigned char c;
	u_int parts[4];
	register u_int *pp = parts;

	c = *src;
	for (;;) {
		/*
		 * Collect number up to ``.''.
		 * Values are specified as for C:
		 * 0x=hex, 0=octal, isdigit=decimal.
		 */
		if (!isdigit(c))
			return (0);
		val = 0; base = 10;
		if (c == '0') {
			c = *++src;
			if (c == 'x' || c == 'X')
				base = 16, c = *++src;
			else if (isdigit(c) && c != '9')
				base = 8;
		}
		/* inet_pton() takes decimal only */
		if (pton && base != 10)
			return (0);
		for (;;) {
			if (isdigit(c)) {
				digit = c - '0';
				if ((int)digit >= base)
					break;
				val = (val * base) + digit;
				c = *++src;
			} else if (base == 16 && isxdigit(c)) {
				digit = c + 10 - (islower(c) ? 'a' : 'A');
				if (digit >= 16)
					break;
				val = (val << 4) | digit;
				c = *++src;
			} else
				break;
		}
		if (c == '.') {
			/*
			 * Internet format:
			 *	a.b.c.d
			 *	a.b.c	(with c treated as 16 bits)
			 *	a.b	(with b treated as 24 bits)
			 *	a	(with a treated as 32 bits)
			 */
			if (pp >= parts + 3)
				return (0);
			*pp++ = val;
			c = *++src;
		} else
			break;
	}
	/*
	 * Check for trailing characters.
	 */
	if (c != '\0' && !isspace(c))
		return (0);
	/*
	 * Concoct the address according to
	 * the number of parts specified.
	 */
	n = pp - parts + 1;
	/* inet_pton() takes dotted-quad only.  it does not take shorthand. */
	if (pton && n != 4)
		return (0);
	switch (n) {

	case 0:
		return (0);		/* initial nondigit */

	case 1:				/* a -- 32 bits */
		break;

	case 2:				/* a.b -- 8.24 bits */
		if (parts[0] > 0xff || val > 0xffffff)
			return (0);
		val |= parts[0] << 24;
		break;

	case 3:				/* a.b.c -- 8.8.16 bits */
		if ((parts[0] | parts[1]) > 0xff || val > 0xffff)
			return (0);
		val |= (parts[0] << 24) | (parts[1] << 16);
		break;

	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
		if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
			return (0);
		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
		break;
	}
	if (dst) {
		val = htonl(val);
		memcpy(dst, &val, INADDRSZ);
	}
	return (1);
}

/* int
 * inet_pton6(src, dst)
 *	convert presentation level address to network order binary form.
 * return:
 *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
 * notice:
 *	(1) does not touch `dst' unless it's returning 1.
 *	(2) :: in a full address is silently ignored.
 * credit:
 *	inspired by Mark Andrews.
 * author:
 *	Paul Vixie, 1996.
 */
inline int inet_pton6(const char *src, u_char *dst)
{
	static const char xdigits_l[] = "0123456789abcdef",
			  xdigits_u[] = "0123456789ABCDEF";
	
	const int IN6ADDRSZ = sizeof(in6_addr);
	const int INT16SZ = sizeof(int16_t);
	u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
	const char *xdigits, *curtok;
	int ch, saw_xdigit;
	u_int val;

	memset((tp = tmp), '\0', IN6ADDRSZ);
	endp = tp + IN6ADDRSZ;
	colonp = NULL;
	/* Leading :: requires some special handling. */
	if (*src == ':')
		if (*++src != ':')
			return (0);
	curtok = src;
	saw_xdigit = 0;
	val = 0;
	while ((ch = *src++) != '\0') {
		const char *pch;

		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
			pch = strchr((xdigits = xdigits_u), ch);
		if (pch != NULL) {
			val <<= 4;
			val |= (pch - xdigits);
			if (val > 0xffff)
				return (0);
			saw_xdigit = 1;
			continue;
		}
		if (ch == ':') {
			curtok = src;
			if (!saw_xdigit) {
				if (colonp)
					return (0);
				colonp = tp;
				continue;
			} else if (*src == '\0')
				return (0);
			if (tp + INT16SZ > endp)
				return (0);
			*tp++ = (u_char) (val >> 8) & 0xff;
			*tp++ = (u_char) val & 0xff;
			saw_xdigit = 0;
			val = 0;
			continue;
		}
		if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
		    inet_pton4(curtok, tp, 1) > 0) {
			tp += INADDRSZ;
			saw_xdigit = 0;
			break;	/* '\0' was seen by inet_pton4(). */
		}
		return (0);
	}
	if (saw_xdigit) {
		if (tp + INT16SZ > endp)
			return (0);
		*tp++ = (u_char) (val >> 8) & 0xff;
		*tp++ = (u_char) val & 0xff;
	}
	if (colonp != NULL) {
		/*
		 * Since some memmove()'s erroneously fail to handle
		 * overlapping regions, we'll do the shift by hand.
		 */
		const int n = tp - colonp;
		int i;

		if (tp == endp)
			return (0);
		for (i = 1; i <= n; i++) {
			endp[- i] = colonp[n - i];
			colonp[n - i] = 0;
		}
		tp = endp;
	}
	if (tp != endp)
		return (0);
	memcpy(dst, tmp, IN6ADDRSZ);
	return (1);
}

/* int
 * inet_pton(af, src, dst)
 *	convert from presentation format (which usually means ASCII printable)
 *	to network format (which is usually some kind of binary format).
 * return:
 *	1 if the address was valid for the specified address family
 *	0 if the address wasn't valid (`dst' is untouched in this case)
 *	-1 if some other error occurred (`dst' is untouched in this case, too)
 * author:
 *	Paul Vixie, 1996.
 */
inline int inet_pton(int af, const char *src, void *dest)
{

	switch (af) {
	case AF_INET:
		return (inet_pton4(src, (u_char*)dest, 1));
	case AF_INET6:
		return (inet_pton6(src, (u_char*)dest));
	default:
#ifdef WIN32
		WSASetLastError(WSAEAFNOSUPPORT);
#else
		errno = EAFNOSUPPORT;
#endif
		cout << "Address family not supported." << endl;
		return (-1);
	}
	/* NOTREACHED */
}


#endif	// defined WIN32

template <typename T>
inline bool SerializeValueType(const T& data, ostream& ostr)
{
	ostr.write((const char*)&data, sizeof(T));
	return !ostr.fail();
}
template <typename T>
inline bool DeserializeValueType(istream& istr, T& data)
{
	istr.read((char*)&data, sizeof(T));
	return !istr.fail();
}
// overload the equal operator of in_addr
inline bool operator==(const in_addr& a1, const in_addr& a2)
{
	return a1.s_addr == a2.s_addr;
}
// overload the not equal operator of in_addr
inline bool operator!=(const in_addr& a1, const in_addr& a2)
{
	return a1.s_addr != a2.s_addr;
}
// overload the less operator of in_addr
inline bool operator < (const in_addr& a1, const in_addr& a2)
{
	return a1.s_addr < a2.s_addr;
}
// overload the equal operator of in6_addr
inline bool operator==(const in6_addr& a1, const in6_addr& a2)
{
#ifdef WIN32
	return IN6_ADDR_EQUAL(&a1, &a2) != 0;
#else
	return IN6_ARE_ADDR_EQUAL(&a1, &a2) != 0;
#endif
}
// overload the unequal operator of in6_addr
inline bool operator!=(const in6_addr& a1, const in6_addr& a2)
{
#ifdef WIN32
	return !IN6_ADDR_EQUAL(&a1, &a2);
#else
	return !IN6_ARE_ADDR_EQUAL(&a1, &a2);
#endif
}
// overload the less operator of in6_addr
inline bool operator<(const in6_addr& a1, const in6_addr& a2)
{
	return memcmp(&a1, &a2, sizeof(in6_addr)) < 0;
}
namespace Internal
{
// convert the ipv4 address in string form to structure form
inline bool ParseAddress(const char* str, in_addr& addr)
{
#ifdef WIN32
	istringstream istr(str);
	int num;
	char c;
	istr >> num;
	addr.S_un.S_un_b.s_b1 = num;
	istr >> c >> num;
	addr.S_un.S_un_b.s_b2 = num;
	istr >> c >> num;
	addr.S_un.S_un_b.s_b3 = num;
	istr >> c >> num;
	addr.S_un.S_un_b.s_b4 = num;
	if(!istr)
	{
		addr.S_un.S_addr = INADDR_NONE;
		return false;
	}
	return true;
#else
	if(inet_pton(AF_INET, str, &addr) <= 0)
	{
		addr.s_addr = INADDR_NONE;
		return false;
	}
	return true;
#endif
}

// convert the ipv6 address from string form to structure form
inline bool ParseAddress(const char* str, in6_addr& addr)
{
	if(inet_pton(AF_INET6, str, &addr) <= 0)
	{
		return false;
	}
	return true;
}

}	//namespace Internal

//IPv4/v6 address class
class IPAddress
{
public:
	explicit IPAddress(sa_family_t f = AF_UNSPEC)
	{
		sa_family = f;
		if(sa_family == AF_INET)
			Addr4().s_addr = INADDR_ANY;
		else if(sa_family == AF_INET6)
			Addr6() = in6addr_any;
		return;
	}
	explicit IPAddress(u_int32_t addr)
	{
		Addr4().s_addr = addr;
		sa_family = AF_INET;
	}
	IPAddress(u_int8_t a1, u_int8_t a2, u_int8_t a3, u_int8_t a4, u_int8_t a5, u_int8_t a6, u_int8_t a7, u_int8_t a8, u_int8_t a9, u_int8_t a10, u_int8_t a11, u_int8_t a12, u_int8_t a13, u_int8_t a14, u_int8_t a15, u_int8_t a16)
	{
		sa_family = AF_INET6;
		u_int8_t* pAddr = (u_int8_t*)&Addr6();
		pAddr[0] = a1;		pAddr[1] = a2;		pAddr[2] = a3;
		pAddr[3] = a4;		pAddr[4] = a5;		pAddr[5] = a6;
		pAddr[6] = a7;		pAddr[7] = a8;		pAddr[8] = a9;
		pAddr[9] = a10;		pAddr[10] = a11;	pAddr[11] = a12;
		pAddr[12] = a13;	pAddr[13] = a14;	pAddr[14] = a15;
		pAddr[15] = a16;
	}
	IPAddress(const IPAddress& addr)
	{
		this->operator=(addr);	
	}
	IPAddress(in_addr addr)
	{
		Addr4() = addr;
		sa_family = AF_INET;
	}
	IPAddress(const in6_addr& addr)
	{
		Addr6() = addr;
		sa_family = AF_INET6;
	}
	IPAddress(const sockaddr& addr)
	{
		this->operator=(addr);
	}
	IPAddress(const sockaddr_in& addr)
	{
		this->operator=(addr);
	}
	IPAddress(const sockaddr_in6& addr)
	{
		this->operator=(addr);
	}
	explicit IPAddress(const char* str)
	{
		this->operator=(str);
	}
	explicit IPAddress(const string& str)
	{
		this->operator=(str);
	}
	IPAddress& operator=(const IPAddress& addr)
	{
		if(this == &addr)
			return *this;
        sa_family = addr.sa_family;
        if(sa_family == AF_INET)
            Addr4() = addr.Addr4();
        else if(sa_family == AF_INET6)
            Addr6() = addr.Addr6();
        return *this;		
	}
	IPAddress& operator=(const char* str)
	{
		if(Internal::ParseAddress(str, Addr6()))
        {
            sa_family = AF_INET6;
        }
        else if(Internal::ParseAddress(str, Addr4()))
        {
            sa_family = AF_INET;
        }
        else
        {
            sa_family = AF_UNSPEC;
        }
		return *this;
	}
	IPAddress& operator=(const string& str)
	{
		return this->operator=(str.c_str());
	}
	IPAddress& operator=(const in_addr& addr)
	{
		Addr4() = addr;
		sa_family = AF_INET;
		return *this;
	}
	IPAddress& operator=(const in6_addr& addr)
	{
		Addr6() = addr;
		sa_family = AF_INET6;
		return *this;
	}
	IPAddress& operator=(const sockaddr& addr)
	{
		assert(addr.sa_family == AF_INET || addr.sa_family == AF_INET6);
		if(addr.sa_family == AF_INET)
		{
			sa_family = AF_INET;
			const sockaddr_in* paddr = (const sockaddr_in*)&addr;
			Addr4() = paddr->sin_addr;
		}
		else
		{
			sa_family = AF_INET6;
			const sockaddr_in6* paddr = (const sockaddr_in6*)&addr;
			Addr6() = paddr->sin6_addr;
		}
		return *this;
	}
	IPAddress& operator=(const sockaddr_in& addr)
	{
		return this->operator=((const sockaddr&)addr);
	}
	IPAddress& operator=(const sockaddr_in6& addr)
	{
		return this->operator=((const sockaddr&)addr);
	}
public:
	static const IPAddress Any4;
	static const IPAddress Any6;
	static const IPAddress Loopback4;
	static const IPAddress Loopback6;
	sa_family_t AddressFamily() const
	{
		return sa_family;
	}
	socklen_t GetLength() const
	{
		return sa_family == AF_INET ? 32 : (sa_family == AF_INET6 ? 128 : 0);
	}
	bool operator == (const IPAddress& addr) const
	{
        if(sa_family != addr.sa_family)
			return false;
		else
		{
			if(sa_family == AF_INET)
				return Addr4() == addr.Addr4();
			else if(sa_family == AF_INET6)
				return Addr6() == addr.Addr6();
			else
				return true;
		}
	}
	bool operator != (const IPAddress& addr) const
	{
		return !this->operator==(addr);
	}
	bool operator < (const IPAddress& addr) const
	{
		if(sa_family < addr.sa_family)
			return true;
		else if(sa_family == addr.sa_family)
		{
			if(sa_family == AF_INET)
				return Addr4() < addr.Addr4();
			else if(sa_family == AF_INET6)
				return Addr6() < addr.Addr6();
			else
				return false;
		}
		else
			return false;
	}
	u_int8_t& operator[](size_t index)
	{
		return reinterpret_cast<u_int8_t*>(&u_addr)[index];
	}
	u_int8_t operator[](size_t index) const
	{
		return reinterpret_cast<const u_int8_t*>(&u_addr)[index];
	}
	operator u_int32_t&()
	{
		return (u_int32_t&)*((u_int32_t*)&Addr4());
	}
	operator u_int32_t() const
	{
		return Addr4().s_addr;
	}
	operator in_addr&()
	{
		return Addr4();
	}
	operator const in_addr&() const
	{
		return Addr4();
	}
	operator in6_addr&()
	{
		return Addr6();
	}
	operator const in6_addr&() const
	{
		return Addr6();
	}
	static u_int16_t H2N(u_int16_t num)
	{
		return htons(num);
	}
	static u_int32_t H2N(u_int32_t num)
	{
		return htonl(num);
	}
	static u_int64_t H2N(u_int64_t num)
	{
		ToBigEndian(num);
		return num;
	}
	static u_int16_t N2H(u_int16_t num)
	{
		return ntohs(num);
	}
	static u_int32_t N2H(u_int32_t num)
	{
		return ntohl(num);
	}
	static u_int64_t N2H(u_int64_t num)
	{
		FromBigEndian(num);
		return num;
	}
	bool IsValid() const
	{
		return sa_family == AF_INET || sa_family == AF_INET6;
	}
	bool IsLoopback() const
	{
		if(sa_family == AF_INET)
			return this->operator[](0) == 127;
		else if(sa_family == AF_INET6)
			return IN6_IS_ADDR_LOOPBACK(&Addr6()) != 0;
		else
			return false;
	}
	bool IsMulticast() const
	{
		if(sa_family == AF_INET)
			return (this->operator[](0) & 0xF0) == 224;
		else if(sa_family == AF_INET6)
			return IN6_IS_ADDR_MULTICAST(&Addr6()) != 0;
		else
			return false;
	}
	bool IsLinkLocal() const
	{
		assert(sa_family == AF_INET6);
		return IN6_IS_ADDR_LINKLOCAL(&Addr6()) != 0;
	}
	bool IsSiteLocal() const
	{
		assert(sa_family == AF_INET6);
		return IN6_IS_ADDR_SITELOCAL(&Addr6()) != 0;
	}
	bool IsV4Mapped() const
	{
		assert(sa_family == AF_INET6);
		return IN6_IS_ADDR_V4MAPPED(&Addr6()) != 0;
	}
	bool Match(const IPAddress& addr, socklen_t len) const
	{
		if(sa_family != addr.sa_family)
			return false;
		socklen_t rem = len % 8;
		len = len / 8;
		if(memcmp(this, &addr, len) != 0)
			return false;
		unsigned char self = ((char*)this)[len];
		unsigned char peer = ((char*)&addr)[len];
		unsigned char mask = (unsigned char)~((1 << (8 - rem)) - 1);
		return ((self & mask) == (peer & mask));
	}
	bool IsV4Compat() const
	{
		assert(sa_family == AF_INET6);
		return IN6_IS_ADDR_V4COMPAT(&Addr6()) != 0;
	}
	bool Parse(const char* str)
	{
		this->operator=(str);
		return AddressFamily() != AF_UNSPEC;
	}
	bool Parse(const string& str)
	{
		this->operator=(str);
		return AddressFamily() != AF_UNSPEC;
	}
	string ToString() const
	{
		char buf[INET6_ADDRSTRLEN];
	    if(inet_ntop(AddressFamily(), Data(), buf, INET6_ADDRSTRLEN) != NULL)
    	{
       		return buf;
    	}
		return "unspec_addr";
	}
	in_addr& Addr4()
	{
		return u_addr.addr4;
	}
	const in_addr& Addr4() const
	{
		return u_addr.addr4;
	}
	in6_addr& Addr6()
	{
		return u_addr.addr6;
	}
	const in6_addr& Addr6() const
	{
		return u_addr.addr6;
	}
	const u_int8_t* Data() const
	{
		return (u_int8_t*)&u_addr;
	}
	u_int8_t* Data()
	{
		return (u_int8_t*)&u_addr;
	}
	bool Serialize(ostream& ostr) const
	{
		// AF_INET6 is defined as 10 under linux but 23 under windows !!!
		// i have 1 represents AF_INET and 2 represents AF_INET6 in the serialization state
		sa_family_t family = H2N((sa_family_t)1);
		if(sa_family == AF_INET)
		{
			SerializeValueType(family, ostr);
			ostr.write((const char*)&u_addr.addr4, 4);
		}
		else if(sa_family == AF_INET6)
		{
			family = H2N((sa_family_t)2);
			SerializeValueType(family, ostr);
			ostr.write((const char*)&u_addr.addr6, 16);
		}
		return !ostr.fail();
	}
	bool Deserialize(istream& istr)
	{
		DeserializeValueType(istr, sa_family);
		sa_family = N2H(sa_family);
		if(sa_family == 1)
		{
			sa_family = AF_INET;
			istr.read((char*)&u_addr.addr4, 4);
		}
		else if(sa_family == 2)
		{
			sa_family = AF_INET6;
			istr.read((char*)&u_addr.addr6, 16);
		}
		return !istr.fail();
	}
private:
	union InternetAddressUnion
	{
		in_addr addr4;
		in6_addr addr6;
	}u_addr;
	sa_family_t	sa_family;
public:
	static const IPAddress Null;
};

inline istream& operator >> (istream& istr, IPAddress& addr)
{
	string str;
	istr >> str;
	if(!addr.Parse(str))
		istr.setstate(ios::failbit);
	return istr;
}
inline ostream& operator << (ostream& ostr, const IPAddress& addr)
{
	ostr << addr.ToString();
	return ostr;
}



class IPEndPoint
{
public:
	IPEndPoint() : port(0)
	{
	}
	IPEndPoint(in_addr _addr, in_port_t _port = 0)
	{
		addr = _addr;
		port = _port;
	}
	IPEndPoint(in6_addr _addr, in_port_t _port = 0)
	{
		addr = _addr;
		port = _port;
	}
	IPEndPoint(sa_family_t family, in_port_t p) : addr(family), port(p)
	{
	}
	IPEndPoint(const IPAddress& a, in_port_t p)
	{
		addr = a;
		port = p;
	}
	IPEndPoint(const string& str, in_port_t _port)
	{
		addr.Parse(str);
		port = _port;
	}
	explicit IPEndPoint(const string& str)
	{
		Parse(str);
	}
	IPEndPoint(const sockaddr& sa)
	{
		this->operator=(sa);
	}
	IPEndPoint(const sockaddr_in& sa)
	{
		this->operator=(sa);
	}
	IPEndPoint(const sockaddr_in6& sa)
	{
		this->operator=(sa);
	}
	IPEndPoint(const IPEndPoint& ep)
	{
		addr = ep.addr;
		port = ep.port;
	}
	static in_port_t	MaxPort()
	{
		return 65535;
	}
	static in_port_t MinPort()
	{
		return 0;
	}
	IPAddress& Address()
	{
		return addr;
	}
	const IPAddress& Address()const 
	{
		return addr;
	}
	void FillSockAddr(sockaddr& a) const
	{
		assert(AddressFamily() == AF_INET || addr.AddressFamily() == AF_INET6);
		if(AddressFamily() == AF_INET)
		{
			sockaddr_in* paddr = (sockaddr_in*)&a;
			memset(&paddr->sin_zero, 0, sizeof(paddr->sin_zero));
			paddr->sin_family = AF_INET;
			paddr->sin_addr = addr;
			paddr->sin_port = htons(port);
		}
		else
		{
			memset(&a, 0, sizeof(sockaddr_in6));
			sockaddr_in6* paddr = (sockaddr_in6*)&a;
			paddr->sin6_family = AF_INET6;
			paddr->sin6_addr = addr;
			paddr->sin6_port = htons(port);
		}
	}
	void FillSockAddr(sockaddr_in& a) const
	{
		assert(AddressFamily() == AF_INET);
		return FillSockAddr((sockaddr&)a);
	}
	void FillSockAddr(sockaddr_in6& a) const
	{
		return FillSockAddr((sockaddr&)a);
	}
	sa_family_t AddressFamily() const
	{
		return addr.AddressFamily();
	}
	in_port_t& Port()
	{
		return port;
	}
	const in_port_t& Port() const
	{
		return port;
	}
	bool operator == (const IPEndPoint& ep) const
	{
		return addr == ep.addr && port == ep.port;
	}
	bool operator != (const IPEndPoint& ep) const
	{
		return addr != ep.addr || port != ep.port;
	}
	bool operator < (const IPEndPoint& ep) const
	{
		return addr < ep.addr ? true : (addr == ep.addr ? port < ep.port : false);
	}
	IPEndPoint& operator = (const IPEndPoint& ep)
	{
        addr = ep.addr;
		port = ep.port;
		return *this;
	}
	IPEndPoint& operator = (const sockaddr_in& sa)
	{
		return this->operator = ((const sockaddr&)sa);
	}
	IPEndPoint& operator = (const sockaddr_in6& sa)
	{
		return this->operator = ((const sockaddr&)sa);
	}
	IPEndPoint& operator = (const sockaddr& sa)
	{
		assert(sa.sa_family == AF_INET || sa.sa_family == AF_INET6);
        if(sa.sa_family == AF_INET)
        {
            sockaddr_in* paddr = (sockaddr_in*)&sa;
            addr = paddr->sin_addr;
            port = ntohs(paddr->sin_port);
        }
        else
        {
            sockaddr_in6* paddr = (sockaddr_in6*)&sa;
            addr = paddr->sin6_addr;
            port = ntohs(paddr->sin6_port);
        }
		return *this;
	}
	bool Parse(const string& str)
	{
		string::size_type index = str.find_last_of(':');
		if(index != string::npos)
		{
			if(!addr.Parse(str.substr(0, index)))
				return false;
			istringstream istr(str.substr(index + 1));
			istr >> port;
			return !istr.fail();
		}
		return false;
	}
	string ToString() const
	{
		ostringstream ostr;
		ostr << addr << ":" << port;
		return ostr.str();
	}
	bool Serialize(ostream& ostr) const
	{
		if(!addr.Serialize(ostr))
			return false;
		in_port_t nport = IPAddress::H2N(port);
		SerializeValueType(nport, ostr);
		return !ostr.fail();
	}
	bool Deserialize(istream& istr)
	{
		if(!addr.Deserialize(istr))
			return false;
		DeserializeValueType(istr, port);
		port = IPAddress::N2H(port);
		return !istr.fail();
	}
private:
	IPAddress	addr;			//address in network order
	in_port_t	port;			//port in host order
public:
	static const IPEndPoint Null;
};

inline istream& operator >> (istream& istr, IPEndPoint& ep)
{
	string str;
	istr >> str;
	if(!ep.Parse(str))
		istr.setstate(ios::failbit);
	return istr;
}

inline ostream& operator << (ostream& ostr, const IPEndPoint& ep)
{
	ostr << ep.ToString();
	return ostr;
}

class IPAddressInfo
{
public:
	IPAddressInfo(){}
	IPAddressInfo(const addrinfo& ai)
	{
		Init(ai);
	}
	IPAddressInfo(const IPAddressInfo& ai)
	{
        HostName = ai.HostName;
		Addresses = ai.Addresses;
	}
	void Init(const addrinfo& ai)
	{
		Clear();
		HostName = (ai.ai_canonname == NULL ? "" : ai.ai_canonname);

		Addresses.insert(IPAddress(*(ai.ai_addr)));
		addrinfo* pai = ai.ai_next;
		while(pai != NULL)
		{
			Addresses.insert(IPAddress(*(pai->ai_addr)));
			pai = pai->ai_next;
		}
	}
	void Clear()
	{
		HostName = "";
		Addresses.clear();
	}
	void Display() const
	{
		cout << "Host name:" << HostName << endl;
		cout << (unsigned int)Addresses.size() << " Addresses:" << endl;
		set<IPAddress>::const_iterator it = Addresses.begin();
		for(; it != Addresses.end(); ++it)
		{
			cout << *it << endl;
		}
	}
public:
	string				HostName;
	set<IPAddress>		Addresses;
};

class Dns
{
public:
	static bool GetAddressInfo(const IPAddress& addr, IPAddressInfo& ai)
	{
		return GetAddressInfo(addr.ToString(), ai);
	}
	static bool GetAddressInfo(const string& hostname, IPAddressInfo& ai)
	{
		addrinfo* presult = NULL;
		if(getaddrinfo(hostname.c_str(), NULL, NULL, &presult) != 0)
		{
			return false;
		}
		assert(presult != NULL);
		ai.Init(*presult);
		freeaddrinfo(presult);
		return true;
	}
	static bool GetHostName(string& name)
	{
		name.resize(PATH_MAX);
		if(gethostname(&name[0], PATH_MAX) == SOCKET_ERROR)
		{
			name.resize(0);
			return false;
		}
		else
		{
			name.resize(strlen(name.c_str()));
			return true;
		}
	}
	static bool GetAddresses(const string& hn, vector<IPAddress>& addresses)
	{
		IPAddressInfo ai;
		if(!GetAddressInfo(hn, ai))
			return false;
		set<IPAddress>::const_iterator it = ai.Addresses.begin();
		for(; it != ai.Addresses.end(); ++it)
		{
			addresses.push_back(*it);
		}
		return true;
	}
};

// enumeration indicate the result of wait
enum WaitType
{
	WT_Timeout	= 1,	
	WT_Error	= 2,	
	WT_Read		= 4,	
	WT_Write	= 8,
	WT_Except	= 16,
};

// we return positive numbers represent the received byte count 
// return 0 indicate the remote side has close the socket
// return -1 to indicate that there has been an error occur during the receive process
// return -2 to indicate just timeout
const int RECEIVE_TIMEOUT = -2;

// Supported protocol type
enum ProtocolType
{
	PT_IP		= IPPROTO_IP,			
	PT_Icmp		= IPPROTO_ICMP,			
	PT_Igmp		= IPPROTO_IGMP,			
	PT_Tcp		= IPPROTO_TCP,			
	PT_Pup		= IPPROTO_PUP,
	PT_Udp		= IPPROTO_UDP,
	PT_Idp		= IPPROTO_IDP,
	PT_IPv6		= IPPROTO_IPV6,
	PT_Routing	= IPPROTO_ROUTING,
	PT_Raw		= IPPROTO_RAW
};

// Supported socket type
enum SocketType
{
	ST_Unknown		= 0,
	ST_Stream		= SOCK_STREAM,
	ST_Dgram		= SOCK_DGRAM,
	ST_Raw			= SOCK_RAW,
	ST_Rdm			= SOCK_RDM,
	ST_Seqpacket	= SOCK_SEQPACKET
};

// Socket option level used in setsockopt and getsockopt functions
enum SocketOptionLevel
{
	SOL_IPv4		= IPPROTO_IP,
	SOL_IPv6		= IPPROTO_IPV6,
	SOL_Socket		= SOL_SOCKET,
	SOL_Udp			= IPPROTO_UDP
};

// socket option names used in setsockopt and getsockopt functions
enum SocketOptionName
{
	SON_AcceptConnection	= SO_ACCEPTCONN,
	SON_AddMemberShip		= IP_ADD_MEMBERSHIP,
	SON_AddSourceMemberShip	= IP_ADD_SOURCE_MEMBERSHIP,
	SON_BlockSource			= IP_BLOCK_SOURCE,
	SON_Broadcast			= SO_BROADCAST,
	SON_Debug				= SO_DEBUG,		
	SON_DontRoute			= SO_DONTROUTE,	
	SON_DropMemberShip		= IP_DROP_MEMBERSHIP,
	SON_DropSourceMemberShip= IP_DROP_SOURCE_MEMBERSHIP,
	SON_Error				= SO_ERROR,
	SON_HeaderIncluded		= IP_HDRINCL,
	SON_IPOptions			= IP_OPTIONS,
	SON_IPTimeToLive		= IP_TTL,
	SON_KeepAlive			= SO_KEEPALIVE,
	SON_Linger				= SO_LINGER,
	SON_MulticastInterface	= IP_MULTICAST_IF,
	SON_MulticastLoopback	= IP_MULTICAST_LOOP,
	SON_MulticastTimeToLive	= IP_MULTICAST_TTL,
	SON_Nodelay				= TCP_NODELAY,
	SON_OutOfBandInline		= SO_OOBINLINE,
	SON_PacketInformation	= IP_PKTINFO,
	SON_ReceiveBuffer		= SO_RCVBUF,
	SON_ReceiveLowWater		= SO_RCVLOWAT,
	SON_ReceiveTimeout		= SO_RCVTIMEO,
	SON_ReuseAddress		= SO_REUSEADDR,
	SON_SendBuffer			= SO_SNDBUF,
	SON_SendLowWater		= SO_SNDLOWAT,
	SON_SendTimeout			= SO_SNDTIMEO,
	SON_Type				= SO_TYPE,
	SON_TypeOfService		= IP_TOS,
	SON_UnblockSource		= IP_UNBLOCK_SOURCE
};

#ifndef WIN32
#define SD_RECEIVE	0
#define SD_SEND		1
#define SD_BOTH		2
#endif

enum SocketShutdown
{
	SS_Send = SD_SEND,
	SS_Recv = SD_RECEIVE,
    SS_Both = SD_BOTH
};

enum SocketFlags
{
	SF_None				= 0,
#ifdef WIN32
	SF_OutOfBand		= 1,
	SF_DontWait			= 2,
	SF_DontRoute		= 4,
	SF_MaxIOVectorLength= 16,
	SF_Partial			= 32768
#else
	SF_OutOfBand		= MSG_OOB,
	SF_DontRoute		= MSG_DONTROUTE,
	SF_DontWait			= MSG_DONTWAIT,
#endif
};

class SocketSet
{
public:
	SocketSet()
	{
		Clear();
	}
	SocketSet(const SocketSet& ss)
	{
		_fds = ss._fds;
		max_fd = ss.max_fd;
	}
	SocketSet& operator=(const SocketSet& ss)
	{
		_fds = ss._fds;
		max_fd = ss.max_fd;
		return *this;
	}
	void Clear ()
	{
		FD_ZERO (&_fds);
		max_fd = -1;
	}
	void Add (SOCKET sock)
	{
		assert(sock != INVALID_SOCKET);
		FD_SET (sock, &_fds);
		if(sock > max_fd)
		{
			max_fd = sock;
		}
	}
	bool Contains (SOCKET sock) const
	{
		assert(sock != INVALID_SOCKET);
		return FD_ISSET (sock, &_fds) != false;
	}
	void Remove(SOCKET sock)
	{
		assert(sock != INVALID_SOCKET);
		FD_CLR(sock, &_fds);
		if(sock == max_fd)		//check if the max socket is removed
		{
			RefreshMaxFd();
		}
	}
	operator ::fd_set * ()
	{
		return &_fds;
	}
	operator ::fd_set & ()
	{
		return _fds;
	}
	SOCKET MaxSocket()
	{
		return max_fd;
	}
protected:
	void RefreshMaxFd()
	{
		while(!FD_ISSET(max_fd, &_fds))
		{
			--max_fd;
		}
	}
protected:
	::fd_set	_fds;
	SOCKET		max_fd;
};

class Socket
{
public:
	static void Init()
	{
#ifdef WIN32
		WSADATA wd;
		WSAStartup(MAKEWORD(2, 2), &wd);
#endif
	}
	static void Cleanup()
	{
#ifdef WIN32
		WSACleanup();
#endif
	}
public:
	Socket(SOCKET _sock = INVALID_SOCKET)
	{
		sock = _sock;
	}
	Socket(const Socket& s)
	{
		sock = s.sock;
	}
	Socket(u_int16_t af, SocketType st, ProtocolType pt)
	{
		Create(af, st, pt);
	}
	bool Create(u_int16_t af, SocketType st, ProtocolType pt)
	{
		assert(af == AF_INET || AF_INET6);
		assert(st == ST_Stream || st == ST_Dgram);
		assert(pt == PT_Tcp || pt == PT_Udp);	
		sock = socket(af, st, pt);
		if(sock == INVALID_SOCKET)
		{
			#ifdef WIN32
			int err = WSAGetLastError();
			assert(err != WSANOTINITIALISED &&
				err != WSAEPROTONOSUPPORT &&
				err != WSAEPROTOTYPE &&
				err != WSAESOCKTNOSUPPORT);
			#endif
			return false;
		}
		else
			return true;
	}
	static Socket CreateTcpServer(const string& strEndPoint, int backlog = 10)
	{
		IPEndPoint ep(strEndPoint);
		return CreateTcpServer(ep, backlog);
	}
	static Socket CreateTcpServer(const string& strAddress, in_port_t port, int backlog = 10)
	{
		IPEndPoint ep(strAddress, port);
		return CreateTcpServer(ep, backlog);
	}
	static Socket CreateTcpServer(const IPAddress& addr, in_port_t port, int backlog = 10)
	{
		IPEndPoint ep(addr, port);
		return CreateTcpServer(ep, backlog);
	}
	static Socket CreateTcpServer(sa_family_t family, in_port_t port, int backlog = 10)
	{
		IPEndPoint ep(family, port);
		return CreateTcpServer(ep, backlog);
	}
	static Socket CreateTcpServer(const IPEndPoint& ep, int backlog = 10)
	{
		assert(ep.AddressFamily() == AF_INET || ep.AddressFamily() == AF_INET6);
		Socket sock;
		if(!sock.Create(ep.AddressFamily(), ST_Stream, PT_Tcp))
		{
			perror("create socket failed in CreateTcpServer");
			return Socket(INVALID_SOCKET);
		}
        if(!sock.Bind(ep))
        {
            perror("bind failed in CreateTcpServer");
			sock.Close();
            return Socket(INVALID_SOCKET);
        }
        if(!sock.Listen(backlog))
        {
            perror("listen failed. in CreateTcpServer");
			sock.Close();
            return Socket(INVALID_SOCKET);
        }
        return sock;
	}
	static Socket CreateTcpClient(const string& strEndPoint, int64_t timeout = LLONG_MAX)
	{
		IPEndPoint ep(strEndPoint);
		return CreateTcpClient(ep, timeout);
	}
	static Socket CreateTcpClient(const string& strAddress, in_port_t port, int64_t timeout = LLONG_MAX)
	{
		IPEndPoint ep(strAddress, port);
		return CreateTcpClient(ep, timeout);
	}
	static Socket CreateTcpClient(const IPAddress& addr, in_port_t port, int64_t timeout = LLONG_MAX)
	{
		IPEndPoint ep(addr, port);
		return CreateTcpClient(ep, timeout);
	}
	static Socket CreateTcpClient(const IPEndPoint& ep, int64_t timeout = LLONG_MAX)
	{
		assert(ep.AddressFamily() == AF_INET || ep.AddressFamily() == AF_INET6);
		Socket sock;
		if(!sock.Create(ep.AddressFamily(), ST_Stream, PT_Tcp))
		{
			perror("create socket failed in CreateTcpClient");
			return Socket(INVALID_SOCKET);
		}
		if(!sock.Connect(ep))
		{
			perror("connect failed in CreateTcpClient");
			sock.Close();
			return Socket(INVALID_SOCKET);
		}
		return sock;
	}
	static Socket CreateUdpSender(sa_family_t family)
	{
		Socket sock(family, ST_Dgram, PT_Udp);
		if(!sock.IsValid())
		{
			perror("create socket failed in CreateUdpServer");
			return Socket(INVALID_SOCKET);
		}
		return sock;
	}
	static Socket CreateUdpReceiver(const string& strEndPoint, bool reuseAddr)
	{
		IPEndPoint ep(strEndPoint);
		return CreateUdpReceiver(ep, reuseAddr);
	}
	static Socket CreateUdpReceiver(const string& strAddress, in_port_t port, bool reuseAddr)
	{
		IPEndPoint ep(strAddress, port);
		return CreateUdpReceiver(ep, reuseAddr);
	}
	static Socket CreateUdpReceiver(const IPAddress& addr, in_port_t port, bool reuseAddr)
	{
		IPEndPoint ep(addr, port);
		return CreateUdpReceiver(ep, reuseAddr);
	}
	static Socket CreateUdpReceiver(sa_family_t family, in_port_t port, bool reuseAddr)
	{
		IPEndPoint ep(family, port);
		return CreateUdpReceiver(ep, reuseAddr);
	}
	static Socket CreateUdpReceiver(const IPEndPoint& ep, bool reuseAddr)
	{
		Socket sock(ep.AddressFamily(), ST_Dgram, PT_Udp);
		if(!sock.IsValid())
		{
			perror("create socket failed in CreateUpdReceiver");
			return Socket(INVALID_SOCKET);
		}
#if defined(WIN32)
		if(ep.Address().IsMulticast())				//bind to a multicast address will fail in windows
		{
			IPAddress anyAddr(ep.AddressFamily());
			if(!sock.Bind(IPEndPoint(anyAddr, ep.Port()), reuseAddr))
			{
				perror("bind socket failed in CreateUdpReceiver");
				return Socket(INVALID_SOCKET);
			}
			return sock;
		}
#endif
		if(!sock.Bind(ep, reuseAddr))
		{
			perror("bind socket failed in CreateUdpReceiver");
			return Socket(INVALID_SOCKET);
		}
		return sock;
	}
	Socket& operator=(SOCKET s)
	{
		sock = s;
		return *this;
	}
	Socket& operator=(const Socket& s)
	{
		sock = s.sock;
		return *this;
	}
	
	//Properties
public:
	u_int16_t	AddressFamily()
	{
		if(sock == INVALID_SOCKET)
			return AF_UNSPEC;
		else
			return LocalEndPoint().AddressFamily();
	}
	SocketType	SockType()
	{
		if(sock == INVALID_SOCKET)
			return ST_Unknown;
		else
		{
			u_int32_t type;
			if(GetSockOption(SOL_Socket, SON_Type, &type, sizeof(type)))
				return (SocketType)type;
			else
				return ST_Unknown;
		}
	}
	int32_t	ReadableBytes()
	{
		int32_t count;
		#ifdef WIN32
		if(ioctlsocket(sock, FIONREAD, (u_long*)&count) != SOCKET_ERROR)
		#else
		if(ioctl(sock, FIONREAD, (int32_t*)&count) != SOCKET_ERROR)
		#endif
			return count;
		else
		{
			Close();
			return -1;
		}
	}
	bool	 Connected()
	{		
		sockaddr_in name;
		socklen_t len = sizeof(name);
		return getpeername(sock, (sockaddr*)&name, &len) != SOCKET_ERROR;
	}
	/*
	u_int16_t GetLingerTime()
	{
		LINGER l;
		if(!GetSockOption(SOL_Socket, SON_Linger, &l, sizeof(l)))
			return -1;			
		if(l.l_onoff)
			return l.l_linger;
		else
			return 0;
	}
	*/
	/*
	bool SetLingerTime(u_int16_t lt)
	{
		LINGER l;
		if(lt == 0)
			l.l_onoff = 0;
		else
			l.l_onoff = 1;
		l.l_linger = lt;
		return SetSockOption(SOL_Socket, SON_Linger, &l, sizeof(l));
	}
	*/
	SOCKET	Handle() const
	{
		return sock;
	}
	operator SOCKET() const
	{
		return sock;
	}
	bool IsValid() const
	{
		return sock != INVALID_SOCKET;
	}
	IPEndPoint	LocalEndPoint() const
	{
		sockaddr_in6 name;
		socklen_t len = sizeof(name);
		if(getsockname(sock, (sockaddr*)&name, &len) == SOCKET_ERROR)
		{
			#ifdef WIN32
			int err = WSAGetLastError();
			assert(err != WSANOTINITIALISED &&
				err != WSAEFAULT &&
				err != WSAENOTSOCK);
			#endif
			return IPEndPoint::Null;
		}
		else
		{
			return IPEndPoint(name);
		}
	}
	IPEndPoint	RemoteEndPoint() const
	{
		sockaddr_in6 name;				//large enough for both v4 and v6 ip address
		socklen_t len = sizeof(name);
		if(getpeername(sock, (sockaddr*)&name, &len) == SOCKET_ERROR)
		{
			#ifdef WIN32
			int err = WSAGetLastError();
			assert(err != WSANOTINITIALISED &&
				err != WSAEFAULT &&
				err != WSAENOTSOCK);
			#endif
			return IPEndPoint::Null;
		}
		else
		{
			return IPEndPoint((sockaddr&)name);
		}
	}
	bool SetSendBufferSize(u_int32_t bufsize)
	{
		return setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufsize, sizeof(bufsize)) != SOCKET_ERROR;
	}
	bool SetRecvBufferSize(u_int32_t bufsize)
	{
		return setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(bufsize)) != SOCKET_ERROR;
	}
	int GetUnicastHops()
	{
		if(!IsValid())
			return -1;
		int hops = 0;
		int optname = 0;
		int level = 0;
		switch(AddressFamily())
		{
		case AF_INET:
			optname = IP_TTL;
			level = IPPROTO_IP;
			break;
		case AF_INET6:
			optname = IPV6_UNICAST_HOPS;
			level = IPPROTO_IPV6;
			break;
		default:
			return -1;
		}
		socklen_t len = (int)sizeof(hops);
		if(getsockopt(sock, level, optname, (char*)&hops, &len) == SOCKET_ERROR)
		{
			cout << "get ttl failed." << endl;
			return -1;
		}
		return hops;
	}
	bool SetUnicastHops(int hops)
	{
		if(!IsValid())
			return false;
		int optname = 0;
		int level = 0;
		switch(AddressFamily())
		{
		case AF_INET:
			optname = IP_TTL;
			level = IPPROTO_IP;
			break;
		case AF_INET6:
			optname = IPV6_UNICAST_HOPS;
			level = IPPROTO_IPV6;
			break;
		default:
			return false;
		}
		if(setsockopt(sock, level, optname, (char*)&hops, sizeof(hops)) == SOCKET_ERROR)
		{
			cout << "set unicast hops failed." << endl;
			return false;
		}
		return true;
	}
public:
	Socket Accept(int64_t timeout = LLONG_MAX)
	{
		if(Wait(timeout, WT_Read) & WT_Read)
		{
			SOCKET newsock = accept(sock, NULL, NULL);
			if(newsock == INVALID_SOCKET)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				assert(err != WSANOTINITIALISED &&
					err != WSAEFAULT &&
					err != WSAEINVAL &&
					err != WSAENOTSOCK &&
					err != WSAEOPNOTSUPP);
				if(err != WSAEMFILE && err != WSAENOBUFS)	
				{
					Close();
				}
				#endif
			}
			return newsock;
		}
		else
		{
			return INVALID_SOCKET;
		}
	}
	Socket Accept(IPEndPoint& ep, int64_t timeout = LLONG_MAX)
	{
		sockaddr_in6 addr;
		socklen_t len = sizeof(addr);
		SOCKET newsock = INVALID_SOCKET;
		if(Wait(timeout, WT_Read) & WT_Read)
		{
			newsock = ::accept(sock, (sockaddr*)&addr, &len);
			if(newsock == INVALID_SOCKET)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				assert(err != WSANOTINITIALISED &&
					err != WSAEFAULT &&
					err != WSAEINVAL &&
					err != WSAENOTSOCK &&
					err != WSAEOPNOTSUPP);
				if(err != WSAEMFILE && err != WSAENOBUFS)			
				{
					Close();
				}
				#endif
			}
			else
				ep = addr;
			return newsock;
		}
		return INVALID_SOCKET;
	}
	void Attach(SOCKET s)
	{
		assert(s != INVALID_SOCKET);
		sock = s;
	}
	SOCKET	Detach()
	{
		SOCKET ret = sock;
		sock = INVALID_SOCKET;
		return ret;
	}
	bool Block(bool block = true)
	{
		int32_t value = (block ? 0 : 1);
		#ifdef WIN32
		if(ioctlsocket(sock, FIONBIO, (u_long*)&value) == SOCKET_ERROR)
		#else
		if(ioctl(sock, FIONBIO, &value) == SOCKET_ERROR)
		#endif
		{
			Close();
			return false;
		}
		return true;
	}
	bool Unblock()
	{
		int32_t value = 1;
		#ifdef WIN32
		if(ioctlsocket(sock, FIONBIO, (u_long*)&value) == SOCKET_ERROR)
		#else
		if(ioctl(sock, FIONBIO, &value) == SOCKET_ERROR)
		#endif
		{
			Close();
			return false;
		}
		return true;
	}
	bool Bind(const IPAddress& addr, in_port_t port, bool ReuseAddr = false)
	{
		return Bind(IPEndPoint(addr, port), ReuseAddr);
	}
	bool Bind(const IPEndPoint& ep, bool ReuseAddr = false)
	{
		if(!ReuseAddress(ReuseAddr))
		{
			return false;
		}
		sockaddr_in6 addr;
		ep.FillSockAddr((sockaddr&)addr);
		if(::bind(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
		{
			Close();
			return false;
		}
		return true;
	}
	bool ReuseAddress(bool reuse = true)
	{
		int32_t value = (reuse ? 1 : 0);
		return SetSockOption(SOL_Socket, SON_ReuseAddress, &value, sizeof(value));
	}
	bool EnableBroadcast(bool enable = true)
	{
		int32_t value = (enable ? 1 : 0);
		return SetSockOption(SOL_Socket, SON_Broadcast, &value, sizeof(value));
	}
	
	bool Close()
	{
		if(sock != INVALID_SOCKET)
		{
			#ifdef WIN32
			bool success = (closesocket(sock) != SOCKET_ERROR);
			#else
			bool success = (close(sock) != SOCKET_ERROR);
			#endif
			sock = INVALID_SOCKET;
			return success;
		}
		return true;
	}
	
	bool Connect(const IPEndPoint& ep, int64_t timeout = LLONG_MAX, bool block = true)
	{
		sockaddr_in6 addr;
		ep.FillSockAddr(addr);
		if(!Unblock())
		{
			return false;
		}
		if(::connect(sock, (sockaddr*)&addr, sizeof(addr)) == 0)
		{
			return true;
		}
		if(Wait(timeout, WT_Write) & WT_Write)
		{
			return Block(block);
		}
		Close();
		return false;
	}
	bool GetSockOption(SocketOptionLevel level, SocketOptionName name, void* optval, size_t optlen)
	{
		#ifdef WIN32
		if(getsockopt(sock, level, name, (char*)optval, (int*)&optlen) == SOCKET_ERROR)
		#else
		if(getsockopt(sock, level, name, (char*)optval, (socklen_t*)&optlen) == SOCKET_ERROR)
		#endif
		{
			#ifdef WIN32
			int wsaerror = WSAGetLastError();
			assert(wsaerror != WSAEFAULT && wsaerror != WSAEINVAL && wsaerror != WSAENOPROTOOPT);
			#endif
			Close();
			return false;
		}
		return true;
	}
	bool SetSockOption(SocketOptionLevel level, SocketOptionName name, void* optval, size_t optlen)
	{
		if(setsockopt(sock, level, name, (char*)optval, (int)optlen) == SOCKET_ERROR)
		{
			#ifdef WIN32
			int wsaerror = WSAGetLastError();
			assert(wsaerror != WSAEFAULT && wsaerror != WSAEINVAL && wsaerror != WSAENOPROTOOPT);
			#endif
			Close();
			return false;
		}
		return true;
	}
	bool Listen(u_int32_t backlog = 10)
	{
		if(::listen(sock, (int)backlog) == SOCKET_ERROR)
		{
			Close();
			return false;
		}
		return true;
	}
	int Wait(int64_t timeout, int mode)
	{
		assert(mode & (WT_Read | WT_Write | WT_Except));
		SocketSet fsRead, fsWrite, fsExcept;
		if(mode & WT_Read)
			fsRead.Add(this->Handle());
		if(mode & WT_Write)
			fsWrite.Add(this->Handle());
		if(mode & WT_Except)
			fsExcept.Add(this->Handle());
		timeval tv;
		assert(timeout >= 0);
		if(timeout > 2147483647000000LL)
		{
			tv.tv_sec = 2147483647;
			tv.tv_usec = 0;
		}
		else
		{
			#ifdef WIN32
			tv.tv_sec = long(timeout / 1000000LL);	
			tv.tv_usec = long(timeout % 1000000LL);
			#else
			tv.tv_sec = time_t(timeout / 1000000LL);
			tv.tv_usec = suseconds_t(timeout % 1000000LL);
			#endif
		}
		int r = select((int)this->Handle() + 1, ((mode & WT_Read) ? (fd_set*)fsRead : NULL), 
						  ((mode & WT_Write) ? (fd_set*)fsWrite : NULL),
						  ((mode & WT_Except) ? (fd_set*)fsExcept : NULL), &tv);
		if(r == 0)
			return WT_Timeout;
		else if(r == SOCKET_ERROR)
		{
			Close();
			return WT_Error;
		}
		else
		{
			int ret = 0;
			
			if(r > 0 && fsRead.Contains(sock))
			{
				ret |= WT_Read;
				-- r;
			}
			if(r > 0 && fsWrite.Contains(sock))
			{
				ret |= WT_Write;
				-- r;
			}
			if(r > 0 && fsExcept.Contains(sock))
			{
				Close();	
				assert(ret == 0);
				ret = WT_Except;
				-- r;
			}
			assert(ret != 0 && r == 0);
			return ret;
		}
	}
	int Receive(void* buf, size_t len, int64_t timeout = LLONG_MAX)
	{
		return Receive(buf, len, SF_None, timeout);
	}
	int Receive(void* buf, size_t len, SocketFlags sf, int64_t timeout = LLONG_MAX)
	{
		if(!IsValid())
			return 0;
		int wait_result = WT_Timeout;
		if((wait_result = Wait(timeout, WT_Read)) & WT_Read)
		{
			int ret = ::recv(sock, (char*)buf, (int)len, sf);
			if(ret < 0)
			{
				Close();
				return SOCKET_ERROR;
			}
			else if(ret == 0)
			{
				Close();
				return 0;
			}
			return ret;
		}
		else if(wait_result & WT_Timeout)
		{
			return RECEIVE_TIMEOUT;
		}
		else								
		{
			return SOCKET_ERROR;
		}
	}
	int Peek(void* buf, size_t len, int64_t timeout = LLONG_MAX)
	{
		return Receive(buf, len, SF_DontWait, timeout);
	}
	int ReceiveFrom(void *buf, size_t len, int64_t timeout = LLONG_MAX, SocketFlags sf = SF_None)
	{
		int wait_result = WT_Timeout;
		if((timeout == LLONG_MAX) || ((wait_result = Wait(timeout, WT_Read)) & WT_Read))
		{
			int ret = recvfrom(sock, (char*)buf, (int)len, (int)sf, NULL, NULL);
			if(ret == SOCKET_ERROR)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				if(err == WSAECONNRESET)
					return 0;
				assert(err != WSANOTINITIALISED &&			
					err != WSAEFAULT &&
					err != WSAEINVAL &&
					err != WSAEISCONN &&
					err != WSAENOTSOCK &&
					err != WSAESHUTDOWN);
				if(err != WSAEWOULDBLOCK)
				#else
				if(errno != EWOULDBLOCK)
				#endif
				{
					Close();
				}
			}
			return ret;
		}
		else if(wait_result & WT_Timeout)			
		{
			return RECEIVE_TIMEOUT;
		}
		else										
		{
			return SOCKET_ERROR;
		}
	}
	int ReceiveFrom(void* buf, size_t len, IPEndPoint& ep, int64_t timeout = LLONG_MAX, SocketFlags sf = SF_None)
	{
		int wait_result = WT_Timeout;
		if((wait_result = Wait(timeout, WT_Read)) & WT_Read)
		{
			sockaddr_in6 addr;
			socklen_t addr_len = sizeof(addr);
			int ret = recvfrom(sock, (char*)buf, (int)len, (int)sf, (sockaddr*)&addr, &addr_len);
			if(ret == SOCKET_ERROR)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				if(err == WSAECONNRESET)
					return 0;
				assert(err != WSANOTINITIALISED &&			
					err != WSAEFAULT &&
					err != WSAEINVAL &&
					err != WSAEISCONN &&
					err != WSAENOTSOCK &&
					err != WSAESHUTDOWN);
				if(err != WSAEWOULDBLOCK)
				#else
				if(errno != EWOULDBLOCK)
				#endif
				{
					Close();
				}
				if(&ep != NULL)
					ep = IPEndPoint::Null;
			}
			else if(&ep != NULL)
				ep = addr;
			return ret;
		}
		else if(wait_result & WT_Timeout)			
		{
			return RECEIVE_TIMEOUT;
		}
		else										
		{
			return SOCKET_ERROR;
		}
	}
	int Send(const void* buf, size_t len, int64_t timeout = LLONG_MAX, SocketFlags sf = SF_None)
	{
		int wait_result = WT_Timeout;
		if((wait_result = Wait(timeout, WT_Write)) & WT_Write)
		{
			int ret = ::send(sock, (const char*)buf, (int)len, (int)sf);
			if(ret == SOCKET_ERROR)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				assert(err != WSANOTINITIALISED &&			
					err != WSAEFAULT &&
					err != WSAENOTCONN &&
					err != WSAENOTSOCK &&
					err != WSAESHUTDOWN &&
					err != WSAEINVAL);
				if(err != WSAEWOULDBLOCK)
				#else
				if(errno != EWOULDBLOCK)
				#endif
				{
					Close();
				}
			}
			return ret;
		}
		else if(wait_result & WT_Timeout)		
		{
			return 0;
		}
		else									
		{
			return SOCKET_ERROR;
		}
	}
	int SendTo(const void* buf, size_t len, const IPEndPoint& ep, int64_t timeout = LLONG_MAX)
	{
		return SendTo(buf, len, ep, SF_None, timeout);
	}
	int SendTo(const void* buf, size_t len, const IPEndPoint& ep, SocketFlags sf, int64_t timeout = LLONG_MAX)
	{
		int wait_result = WT_Timeout;
		if((timeout == LLONG_MAX) || ((wait_result = Wait(timeout, WT_Write)) & WT_Write))
		{
			sockaddr_in6 addr;
			ep.FillSockAddr((sockaddr&)addr);
			int ret = ::sendto(sock, (const char*)buf, (int)len, (int)sf, (sockaddr*)&addr, sizeof(addr));
			if(ret == SOCKET_ERROR)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				assert(err != WSANOTINITIALISED && 
					err != WSAEACCES &&
					err != WSAEFAULT &&
					err != WSAEINVAL &&
					err != WSAENOTSOCK &&
					err != WSAESHUTDOWN &&
					err != WSAEMSGSIZE &&
					err != WSAEADDRNOTAVAIL &&
					err != WSAEAFNOSUPPORT &&
					err != WSAEDESTADDRREQ);
				if(err != WSAEWOULDBLOCK)
				#else
				if(errno != EWOULDBLOCK)
				#endif
				{
					Close();
				}
			}
			return ret;
		}
		else if(wait_result & WT_Timeout)
		{
			return 0;
		}
		else
		{
			return SOCKET_ERROR;
		}
	}
	
	bool Shutdown(SocketShutdown how = SS_Both)
	{
		if(sock != INVALID_SOCKET)
		{
			if(shutdown(sock, (int)how) == SOCKET_ERROR)
			{
				#ifdef WIN32
				int err = WSAGetLastError();
				assert(err != WSANOTINITIALISED &&
					err != WSAEINVAL &&
					err != WSAENOTCONN &&
					err != WSAENOTSOCK);
				#endif
				Close();
				return false;
			}
		}
		return true;
	}
	// multicast properties
	int GetMulticastInterface()
	{
		switch (AddressFamily()) 
		{
		case AF_INET: 
			{
				/* TODO: similar to mcast_set_if() */
				return(SOCKET_ERROR);
			}
		case AF_INET6: 
			{
				u_int		idx;
				socklen_t	len;
		
				len = sizeof(idx);
				if (getsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&idx, &len) < 0)
					return(SOCKET_ERROR);
				return(idx);
			}
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return(SOCKET_ERROR);
		}
	}
	/*
	bool SetMulticastInterface(const char* ifname, u_int ifindex)
	{
		switch (AddressFamily())
		{
		case AF_INET: 
			{
				struct in_addr	inaddr;
				if (ifindex <= 0 && ifname == NULL)
				{
					inaddr.s_addr = htonl(INADDR_ANY);	// remove prev. set default
				}
				else
				{
					ifreq		ifreq;
					if(ifindex > 0)
					{
						if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) 
						{
							errno = ENXIO;	// i/f index not found 
							return false;
						}
					}
					else
					{
						strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);	
					}
					if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0)
						return false;
					inaddr = ((sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
				}		
				return(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,	&inaddr, sizeof(struct in_addr)) == 0);
			}
		case AF_INET6: 
			{
				u_int	idx;
		
				if ( (idx = ifindex) == 0) {
					if (ifname == NULL) {
						errno = EINVAL;	// must supply either index or name
						return false;
					}
					if ( (idx = if_nametoindex(ifname)) == 0) {
						errno = ENXIO;	// i/f name not found 
						return false;
					}
				}
				return(setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,	&idx, sizeof(idx)) == 0);
			}	
		default:
			errno = EAFNOSUPPORT;
			return false;
		}
	}
	*/
	int GetMulticastHops()
	{
		switch (AddressFamily()) 
		{
		case AF_INET: 
			{
				u_char		ttl;
				socklen_t	len;
		
				len = sizeof(ttl);
				if (getsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, &len) < 0)
					return(SOCKET_ERROR);
				return(ttl);
			}
		case AF_INET6: 
			{
				int			hop;
				socklen_t	len;
		
				len = sizeof(hop);
				if (getsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&hop, &len) < 0)
					return(SOCKET_ERROR);
				return(hop);
			}
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return(SOCKET_ERROR);
		}
	}
	int SetMulticastHops(int val)
	{
		switch (AddressFamily()) 
		{
		case AF_INET: 
			{
				u_char		ttl;
		
				ttl = val;
				return(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl)) == 0);
			}
		case AF_INET6: 
			{
				int		hop;
		
				hop = val;
				return(setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&hop, sizeof(hop)) == 0);
			}
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return false;
		}
	}
	bool IfMulticastLoopback()
	{
		switch (AddressFamily()) 
		{
		case AF_INET:
			{
				u_char		flag;
				socklen_t	len;
		
				len = sizeof(flag);
				if (getsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&flag, &len) < 0)
					return(false);
				return(flag != 0);
			}
		case AF_INET6: 
			{
				u_int		flag;
				socklen_t	len;
		
				len = sizeof(flag);
				if (getsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char*)&flag, &len) < 0)
					return(false);
				return(flag != 0);
			}	
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return false;
		}
	}
	int SetMulticastLoopback(bool onoff = true)
	{
		switch (AddressFamily()) 
		{
		case AF_INET: 
			{
				u_char		flag;
		
				flag = (onoff ? 1 : 0);
				return(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&flag, sizeof(flag)) == 0);
			}
		case AF_INET6: 
			{
				u_int		flag;
		
				flag = (onoff ? 1 : 0);
				return(setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&flag, sizeof(flag)) == 0);
			}
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return false;
		}
	}
#if defined(WIN32)
	bool JoinGroup(const IPAddress& group)
	{
		switch (group.AddressFamily()) 
		{
		case AF_INET: 
		{
			struct ip_mreq	mreq;
	
			mreq.imr_multiaddr = group;
			mreq.imr_interface.s_addr = htonl(INADDR_ANY);		// just support limited function for windows

			return(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == 0);
		}
		case AF_INET6: 
		{
			struct ipv6_mreq	mreq6;
	
			mreq6.ipv6mr_multiaddr = group;
			mreq6.ipv6mr_interface = 0;				// just support limited function for windows
	
			return(setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char*)&mreq6, sizeof(mreq6)) == 0);
		}
		default:
			WSASetLastError(WSAEAFNOSUPPORT);
			cout << "Address family not supported." << endl;
			return false;
		}
	}
	bool JoinSourceGroup(const IPAddress& source, const IPAddress& group)
	{
		switch (AddressFamily())
		{
		case AF_INET: 
			{
				ip_mreq_source	mreq;
		
				mreq.imr_multiaddr = group;
				mreq.imr_sourceaddr = source;
				mreq.imr_interface.s_addr = htonl(INADDR_ANY);		// limited for windows
				
				return(setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == 0);
			}
		/* //windows doesn't support ssm under IPv6
		case AF_INET6: // IPv6 source-specific API is MCAST_JOIN_SOURCE_GROUP
			{
				assert(source.AddressFamily() == AF_INET6 && group.AddressFamily() == AF_INET6);
				struct group_source_req req;
				
				req.gsr_interface = 0;
				sockaddr_in6 addr;
				memset(&addr, 0, sizeof(addr));
				addr.sin6_family = AF_INET6;
				addr.sin6_addr = group;
				memcpy(&req.gsr_group, &addr, sizeof(addr));
				addr.sin6_addr = source;
				memcpy(&req.gsr_source, &addr, sizeof(addr));
				return (setsockopt(sock, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) == 0);
			}
		*/
		default:
			WSASetLastError(WSAEAFNOSUPPORT);
			cout << "Address family not supported." << endl;
			return false;
		}
	}
#else
	bool JoinGroup(const IPAddress& group, const string& ifname)
	{
		switch (group.AddressFamily())
		{
		case AF_INET:
		{
			struct ip_mreq	mreq;
	
			mreq.imr_multiaddr = group;
	
			struct ifreq	 ifreq;
			strncpy(ifreq.ifr_name, ifname.c_str(), IFNAMSIZ);
			if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0)
				return false;
			mreq.imr_interface = ((sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
			
			return(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == 0);
		}
		case AF_INET6: 
		{
			struct ipv6_mreq	mreq6;
	
			mreq6.ipv6mr_multiaddr = group;
			
			if ((mreq6.ipv6mr_interface = if_nametoindex(ifname.c_str())) == 0) 
			{
				errno = ENXIO;	// i/f name not found
				return false;
			}
			return(setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0);
		}
		default:
			errno = EAFNOSUPPORT;
			return false;
		}
	}
	bool JoinGroup(const IPAddress& group, u_int ifindex = 0)
	{
		switch (group.AddressFamily()) 
		{
		case AF_INET: 
		{
			struct ip_mreq	mreq;
	
			mreq.imr_multiaddr = group;
	
			if(ifindex == 0)
			{
				mreq.imr_interface.s_addr = htonl(INADDR_ANY);
			}
			else
			{
				struct ifreq		ifreq;
				if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) 
				{
					errno = ENXIO;	// i/f index not found
					return false;
				}
				if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0)
					return false;
				mreq.imr_interface = ((sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
			}
			return(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == 0);
		}
		case AF_INET6: 
		{
			struct ipv6_mreq	mreq6;
	
			mreq6.ipv6mr_multiaddr = group;
	
			if (ifindex > 0) 
			{
				mreq6.ipv6mr_interface = ifindex;
			}
			else
				mreq6.ipv6mr_interface = 0;
	
			return(setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0);
		}
		default:
			errno = EAFNOSUPPORT;
			return false;
		}
	}
	bool JoinSourceGroup(const IPAddress& source, const IPAddress& group, const string& ifname)
	{
		switch (AddressFamily())
		{
		case AF_INET: 
			{
				ip_mreq_source	mreq;
		
				mreq.imr_multiaddr = group;
				mreq.imr_sourceaddr = source;
		
				struct ifreq	 ifreq;
				strncpy(ifreq.ifr_name, ifname.c_str(), IFNAMSIZ);
				if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0)
					return false;
				mreq.imr_interface = 	((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
		
				return(setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq)) == 0);
			}
		case AF_INET6: // IPv6 source-specific API is MCAST_JOIN_SOURCE_GROUP
			{
				assert(source.AddressFamily() == AF_INET6 && group.AddressFamily() == AF_INET6);
				struct group_source_req req;
				if((req.gsr_interface = if_nametoindex(ifname.c_str())) == 0) 
				{
					errno = ENXIO;	// i/f name not found
					return false;
				}
				sockaddr_in6 addr;
				memset(&addr, 0, sizeof(addr));
				addr.sin6_family = AF_INET6;
				addr.sin6_addr = group;
				memcpy(&req.gsr_group, &addr, sizeof(addr));
				addr.sin6_addr = source;
				memcpy(&req.gsr_source, &addr, sizeof(addr));
				return (setsockopt(sock, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) == 0);
			}
		default:
			errno = EAFNOSUPPORT;
			return false;
		}
	}
	bool JoinSourceGroup(const IPAddress& source, const IPAddress& group, u_int ifindex = 0)
	{
		switch (AddressFamily())
		{
		case AF_INET: 
			{
				ip_mreq_source	mreq;
		
				mreq.imr_multiaddr = group;
				mreq.imr_sourceaddr = source;
		
				if(ifindex == 0)
					mreq.imr_interface.s_addr = htonl(INADDR_ANY);
				else
				{
					struct ifreq	 ifreq;
					if (if_indextoname(ifindex, ifreq.ifr_name) == NULL) 
					{
						errno = ENXIO;	// i/f index not found
						return false;
					}
					if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0)
						return false;
					mreq.imr_interface = 	((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
				}
		
				return(setsockopt(sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &mreq, sizeof(mreq)) == 0);
			}
		case AF_INET6: // IPv6 source-specific API is MCAST_JOIN_SOURCE_GROUP
			{
				assert(source.AddressFamily() == AF_INET6 && group.AddressFamily() == AF_INET6);
				struct group_source_req req;
				if (ifindex > 0) 
				{
					req.gsr_interface = ifindex;
				}
				else
					req.gsr_interface = 0;
				sockaddr_in6 addr;
				memset(&addr, 0, sizeof(addr));
				addr.sin6_family = AF_INET6;
				addr.sin6_addr = group;
				memcpy(&req.gsr_group, &addr, sizeof(addr));
				addr.sin6_addr = source;
				memcpy(&req.gsr_source, &addr, sizeof(addr));
				return (setsockopt(sock, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) == 0);
			}
		default:
			errno = EAFNOSUPPORT;
			return false;
		}
	}
#endif
	bool LeaveGroup(const IPAddress& group)
	{
		switch (AddressFamily())
		{
		case AF_INET: 
		{
			struct ip_mreq		mreq;
	
			mreq.imr_multiaddr = group;
			mreq.imr_interface.s_addr = htonl(INADDR_ANY);
			return(setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == 0);
		}
		case AF_INET6: 
		{
			struct ipv6_mreq	mreq6;
	
			mreq6.ipv6mr_multiaddr = group;
			mreq6.ipv6mr_interface = 0;
			return(setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (const char*)&mreq6, sizeof(mreq6)) == 0);
		}	
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return false;
		}
	}
	bool LeaveSourceGroup(const IPAddress& source, const IPAddress& group)
	{
		switch (AddressFamily()) 
		{
		case AF_INET: 
			{
				struct ip_mreq_source	mreq;
		
				mreq.imr_multiaddr = group;
				mreq.imr_sourceaddr = source;
				mreq.imr_interface.s_addr = htonl(INADDR_ANY);
		
				return(setsockopt(sock, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) == 0);
			}
#if !defined(WIN32)		// windows doesn't support ssm
		case AF_INET6: // IPv6 source-specific API is MCAST_LEAVE_SOURCE_GROUP
			{
				group_source_req req;
				req.gsr_interface = 0;
				sockaddr_in6 addr;
				memset(&addr, 0, sizeof(addr));
				addr.sin6_family = AF_INET6;
				addr.sin6_addr = group;
				memcpy(&req.gsr_group, &addr, sizeof(addr));
				addr.sin6_addr = source;
				memcpy(&req.gsr_source, &addr, sizeof(addr));
				return (setsockopt(sock, IPPROTO_IPV6, MCAST_LEAVE_SOURCE_GROUP, &req, sizeof(req)) == 0);
			}
#endif
		default:
#ifdef WIN32
			WSASetLastError(WSAEAFNOSUPPORT);
#else
			errno = EAFNOSUPPORT;
#endif
			cout << "Address family not supported." << endl;
			return false;
		}
	}
public:
	
	static int Select(list<Socket>* checkRead, list<Socket>* checkWrite, list<Socket>* checkExcept, int64_t wait = LLONG_MAX)
	{
		SocketSet fsRead, fsWrite, fsExcept;
		list<Socket>::iterator it;
		if(checkRead != NULL)
		{
			it = checkRead->begin();
			for(; it != checkRead->end(); ++it)
			{
				fsRead.Add(it->Handle());
			}
		}
		if(checkWrite != NULL)
		{
			it = checkWrite->begin();
			for(; it != checkWrite->end(); ++it)
			{
				fsWrite.Add(it->Handle());
			}
		}
		if(checkExcept != NULL)
		{
			it = checkExcept->begin();
			for(; it != checkExcept->end(); ++it)
			{
				fsExcept.Add(it->Handle());
			}
		}
		timeval timeout;
		if(wait > 2147483647000000LL)
		{
			timeout.tv_sec = 2147483647;
			timeout.tv_usec = 0;
		}
		else
		{
            #ifdef WIN32
            timeout.tv_sec = long(wait / 1000000LL);
            timeout.tv_usec = long(wait % 1000000LL);
            #else
			timeout.tv_sec = time_t(wait / 1000000LL);
			timeout.tv_usec = suseconds_t(wait % 1000000LL);
			#endif
		}
		int max_fd = max(max(fsRead.MaxSocket(), fsWrite.MaxSocket()), fsExcept.MaxSocket());
		int ret = select(max_fd + 1, fsRead, fsWrite, fsExcept, &timeout);
		if(ret == SOCKET_ERROR)
			return ret;
		if(checkRead != NULL)
		{
			it = checkRead->begin();
			while(it != checkRead->end())
			{
				if(!fsRead.Contains(it->Handle()))
				{
					it = checkRead->erase(it);
				}
				else
					++it;
			}
		}
		if(checkWrite != NULL)
		{
			it = checkWrite->begin();
			while(it != checkWrite->end())
			{
				if(!fsWrite.Contains(it->Handle()))
				{
					it = checkWrite->erase(it);
				}
				else
					++it;
			}
		}
		if(checkExcept != NULL)
		{
			it = checkExcept->begin();
			while(it != checkExcept->end())
			{
				if(!fsExcept.Contains(it->Handle()))
				{
					it = checkExcept->erase(it);
				}
				else
					++it;
			}
		}
		return ret;
	}
public:
	static const Socket Null;
private:
	SOCKET sock;
};

class InterfaceInfo
{
public:
	string		Name;
	IPAddress	Address;
	IPAddress	BroadcastAddress;
	IPAddress	NetworkMask;
	IPAddress	DestAddress;
	int32_t		MTU;
	int16_t		Flags;
public:
	InterfaceInfo()
	{
		MTU = 0;
		Flags = 0;
	}
	InterfaceInfo(const InterfaceInfo& ii)
	{
		this->operator=(ii);
	}
	InterfaceInfo& operator=(const InterfaceInfo& ii)
	{
		if(this == &ii)
			return *this;
		Name = ii.Name;
		Address = ii.Address;
		BroadcastAddress = ii.BroadcastAddress;
		NetworkMask= ii.NetworkMask;
		DestAddress = ii.DestAddress;
		MTU = ii.MTU;
		Flags = ii.Flags;
		return *this;
	}
	void Display()
	{
		cout << Name << endl;
		cout << "MTU:" << MTU << endl;
		cout << "Flags:";
		if((Flags & IFF_UP) != 0)
			cout << " UP";
		if((Flags & IFF_BROADCAST) != 0)
			cout << " BROADCAST";
		if((Flags & IFF_MULTICAST) != 0)
			cout << " MULTICAST";
		if((Flags & IFF_LOOPBACK) != 0)
			cout << " LOOPBACK";
		if((Flags & IFF_POINTTOPOINT) != 0)
			cout << " POINTOPOINT";
#if !defined(WIN32)
		if((Flags & IFF_RUNNING) != 0)
			cout << " RUNNING";
#endif
		cout << endl;
		cout << "unicast address:" << Address << endl;
		cout << "network mask:" << NetworkMask << endl;
		if((Flags & IFF_BROADCAST) != 0)
		{
			cout << "broadcast address:" << BroadcastAddress << endl;
		}
		if((Flags & IFF_POINTTOPOINT) != 0)
		{
			cout << "p2p destination address:" << DestAddress << endl;
		}
	}
};
#if !defined(WIN32)

class NetworkConfig
{
public:
	static bool GetInterfaceConfig(list<InterfaceInfo>& lii, int16_t FlagIn = IFF_UP, int16_t FlagEx = 0)
	{
		SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
		if(sock == INVALID_SOCKET)
		{
			perror("Create socket failed in GetInterfaceConfig");
			return false;
		}
		ifconf ifc;
		memset(&ifc, 0, sizeof(ifc));
		char* buf = NULL;
    	int lastDataLen = 0;
		int bufLen = 100 * sizeof(ifreq);     // initial buffer size guess
     	for ( ; ; ) 
		{
			buf = new char[bufLen];
			ifc.ifc_len = bufLen;
			ifc.ifc_buf = buf;
         	if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
			{
            	if (errno != EINVAL || lastDataLen != 0)
				{
					perror("Unexpected error when calling ioctl in GetInterfaceConfig");
					return false;
				}
			}
			else
			{
				if (ifc.ifc_len == lastDataLen)
					break;          // success, len has not changed 
				lastDataLen = ifc.ifc_len;
			}
			bufLen += 10 * sizeof(ifreq);     // increment
			delete [] buf;
		}
		ifreq* preq = ifc.ifc_req;
		InterfaceInfo ii;
		cout << "lastDataLen:" << lastDataLen << endl;
		while(preq < ifc.ifc_req + lastDataLen)
		{
			ifreq* pcur = preq;
			int offset = 0;
			#ifdef   HAVE_SOCKADDR_SA_LEN
          	offset = max(sizeof(sockaddr), ifcur->ifr_addr.sa_len);
 			#else
			switch (pcur->ifr_addr.sa_family)
			{
			
			case AF_INET6:
				offset = sizeof(struct sockaddr_in6);
				break;
			case AF_INET:
			default:
				offset = sizeof(struct sockaddr);
				break;
			}
			#endif
			cout << "offset is :" << offset << endl;
			cout << "the size of ifreq:" << sizeof(ifreq) << " new offset:" << sizeof(pcur->ifr_name) + offset << endl;
			preq = (ifreq*)(((char*)pcur) + sizeof(pcur->ifr_name) + offset);
			if(pcur->ifr_addr.sa_family != AF_INET && pcur->ifr_addr.sa_family != AF_INET6)
			{
				cout << "address family " << pcur->ifr_addr.sa_family << " not supported, ignored." << endl;
				continue;
			}
			// Get name
			ii.Name = pcur->ifr_name;
			// Get unicast address
			ii.Address = pcur->ifr_addr;
			// Get flags
			ifreq ifrcopy = *pcur;
			ioctl(sock, SIOCGIFFLAGS, &ifrcopy);
			ii.Flags = ifrcopy.ifr_flags;
			if(((ii.Flags & FlagIn) != FlagIn) || ((ii.Flags & FlagEx) != 0))
			{
				cout << "Flags doesn't fit, ignore." << endl;
				continue;
			}
			// Get MTU
			ioctl(sock, SIOCGIFMTU, &ifrcopy);
			ii.MTU = ifrcopy.ifr_mtu;
			//Get broadcast address
			if((ii.Flags & IFF_BROADCAST) != 0)
			{
				ioctl(sock, SIOCGIFBRDADDR, &ifrcopy);
				if(ifrcopy.ifr_broadaddr.sa_family == AF_INET || ifrcopy.ifr_broadaddr.sa_family == AF_INET6)
					ii.BroadcastAddress = ifrcopy.ifr_broadaddr;
			}
			// Get destination address of point to point type interface
			if(ii.Flags & IFF_POINTOPOINT)
			{
				ioctl(sock, SIOCGIFDSTADDR, &ifrcopy);
				if(ifrcopy.ifr_dstaddr.sa_family == AF_INET || ifrcopy.ifr_dstaddr.sa_family == AF_INET6)
					ii.DestAddress = ifrcopy.ifr_dstaddr;
			}
			// Get network mask
			ioctl(sock, SIOCGIFNETMASK, &ifrcopy);
			if(ifrcopy.ifr_netmask.sa_family == AF_INET || ifrcopy.ifr_netmask.sa_family == AF_INET6)
				ii.NetworkMask = ifrcopy.ifr_netmask;
			lii.push_back(ii);
		}
		delete [] buf;
		return true;
	}
};

#endif

}		// namespace kascale

#endif  //!defined KASCALE_SOCKET_H

